///<reference types="@i3yun/viewer" />
///<reference types="@i3yun/viewer.markupdiv" />
///<reference types="@i3yun/viewer.transform-controls" />
///<reference types="@i3yun/viewer.tilemaps" />
import { AppSetting } from '../AppSetting';
import { Container } from '../Container';
import { HelperTool } from './Common';

export class ViewerService {
    private AppSetting = Container.defineProperty(AppSetting);

    private ViewerPluginScriptUrls = [
        "@i3yun/viewer.markupdiv/dist/extensions/Sippreep.Extensions.Markup3D.js",
        "@i3yun/viewer.transform-controls/dist/extensions/Sippreep.Extensions.TransformControls.js",
        "@i3yun/viewer.tilemaps/dist/extensions/Sippreep.Extensions.TileMaps.js",
        "@i3yun/viewer.nodeoffhacks/dist/extensions/Sippreep.Extensions.NodeOffHack.js",
    ];
    private ViewerPlugins = [
        "Sippreep.Extensions.NodeOffHack.NodeOffHackExtension"
    ];
    private ViewerScriptUrl = "@i3yun/viewer/dist/Sippreep.js";
    viewer: Sippreep.Viewing.Viewer3D = HelperTool.GetNull();
    ViewerPromise: Promise<Sippreep.Viewing.Viewer3D> = HelperTool.GetNull();
    /**
     * @deprecated ViewerPromise替代
     */
    InitPromise: Promise<void> = HelperTool.GetNull();
    Init() {
        this.ViewerPromise = this.createViewer();
        this.InitPromise = (async () => {
            this.viewer = await this.ViewerPromise;
        })();
    }

    async getMarkup3D() {
        let viewer = await this.ViewerPromise;
        let temp = await viewer.loadExtension('Sippreep.Extensions.MarkupDiv.Markup3DExtension');
        return temp as any as Sippreep.Extensions.MarkupDiv.Markup3DExtension;
    }
    async getTransformControls() {
        let viewer = await this.ViewerPromise;
        let temp = await viewer.loadExtension('Sippreep.Extensions.TransformControls.TransformControlsExtension');
        return temp as any as Sippreep.Extensions.TransformControls.ITransformControlsExtension;
    }
    async getTileMap() {
        let viewer = await this.ViewerPromise;
        let temp = await viewer.loadExtension('Sippreep.Extensions.TileMaps.TileMapExtension');
        return temp as any as Sippreep.Extensions.TileMaps.TileMapExtension;
    }
    /**
     * 创建视图
     * @returns
     */
    private async createViewer() {
        let baseUrl = this.AppSetting.ViewerScriptBaseUrl;
        await HelperTool.loadScript(HelperTool.getFullUrl(this.ViewerScriptUrl, baseUrl));
        await Sippreep.Initializer();
        await Promise.all(this.ViewerPluginScriptUrls.map(_ => HelperTool.loadScript(HelperTool.getFullUrl(_, baseUrl))));
        //创建3D视图
        let viewer_element = document.getElementById(this.AppSetting.ViewerElementId) as HTMLElement;
        let viewer = this.AppSetting.ViewerEnableGui == "1"
            ? new Sippreep.Viewing.GuiViewer3D(viewer_element, { extensions: this.ViewerPlugins })
            : new Sippreep.Viewing.Viewer3D(viewer_element, { extensions: this.ViewerPlugins });
        let errorCode = -1;
        //启动并检查WebGL
        if (this.AppSetting.ViewerEnableGL2) {
            errorCode = viewer.start();
        }
        else {
            //@ts-ignore
            errorCode = viewer.start(undefined, undefined, undefined, undefined, {
                webglInitParams: {
                    useWebGL2: false
                }
            });
        }
        if (errorCode > 0) {
            throw new Error('Failed to create a Viewer: WebGL not supported.');
        }
        return viewer;
    }

    async userFunction<Input, Output>(
        model: Sippreep.Viewing.Model,
        callback: (pdb: Sippreep.Viewing.PropertyDatabase, userData: Input) => Output,
        userData: Input
    ): Promise<Output> {
        let userFunctionStr = `function userFunction(pdb,data){
            return (${callback.toString()})(pdb,data);
        }`
        return await model.getPropertyDb().executeUserFunction(userFunctionStr, userData);
    }
}